Fancy Maps
This week, we’ll make our maps zoom-able and interactive with the leaflet package.
Here’s a demonstration, plotting the county-level 2020 presidential election results for each county in Georgia.1 First, load all the packages we need:
Next, we’ll get our map data from the tigris package. The format of this data is called a Simple Feature, or sf object. It is a more compact way of representing GIS data, and is quickly becoming the standard way to do things.
Simple feature collection with 6 features and 17 fields
geometry type: MULTIPOLYGON
dimension: XY
bbox: xmin: -85.46221 ymin: 31.01044 xmax: -81.73169 ymax: 34.58748
geographic CRS: NAD83
STATEFP COUNTYFP COUNTYNS GEOID NAME NAMELSAD LSAD
16 13 189 00348794 13189 McDuffie McDuffie County 06
53 13 025 00351605 13025 Brantley Brantley County 06
54 13 171 00326713 13171 Lamar Lamar County 06
83 13 115 00353665 13115 Floyd Floyd County 06
102 13 273 00352238 13273 Terrell Terrell County 06
103 13 063 01672399 13063 Clayton Clayton County 06
CLASSFP MTFCC CSAFP CBSAFP METDIVFP FUNCSTAT ALAND AWATER
16 H1 G4020 <NA> 12260 <NA> A 666848710 23114025
53 H1 G4020 <NA> 15260 <NA> A 1147949245 10297607
54 H1 G4020 122 12060 <NA> A 475264443 6044329
83 H1 G4020 122 40660 <NA> A 1320434485 22384089
102 H1 G4020 <NA> 10500 <NA> A 869559691 5087422
103 H1 G4020 122 12060 <NA> A 366946710 6972579
INTPTLAT INTPTLON geometry
16 +33.4796231 -082.4787331 MULTIPOLYGON (((-82.44998 3...
53 +31.1973339 -081.9829779 MULTIPOLYGON (((-81.91012 3...
54 +33.0744405 -084.1466893 MULTIPOLYGON (((-84.24837 3...
83 +34.2636918 -085.2136851 MULTIPOLYGON (((-85.24134 3...
102 +31.7771909 -084.4394464 MULTIPOLYGON (((-84.56317 3...
103 +33.5426863 -084.3555727 MULTIPOLYGON (((-84.45856 3...
Notice that this may take a little while, because it’s downloading the shape data from the Census. Next we’ll merge that map data with the county-level election results.
# load data from project folder
load('../data/county-results-2020-for-map.RData')
# we're going to merge by fips code, so
# make sure that the fips code in each dataset
# is named the same thing and is in the same format
county_map <- mutate(county_map,
fips = as.numeric(GEOID))
counties_2020 <- mutate(counties_2020,
fips = as.numeric(county_fips))
# join the map data and the election results data together
d <- left_join(county_map, counties_2020, by = 'fips')
We can plot sf objects with ggplot using the geom_sf() layer.
# define the hex color codes for Democratic Blue and Republican Red
party_colors <- c("#CB454A", 'gray', "#2E74C0")
ggplot(data = d,
mapping = aes(fill = percent_biden)) +
geom_sf() +
scale_fill_gradient2(low = party_colors[1],
mid = party_colors[2],
high = party_colors[3],
midpoint = 50) +
theme_map() +
theme(legend.position = 'bottom') +
labs(fill = 'Biden Two-Party Vote Share')

And we can make an interactive map with leaflet(). See here for instructions on modifying the color palette, and here for the complete list of base maps you can add.
# create the color scheme
pal <- colorNumeric(
palette = party_colors,
domain = d$percent_biden)
p <- leaflet(data = d) %>%
# add the county polygons, with fill color based on Biden vote share and label with county name
addPolygons(fillColor = ~pal(percent_biden),
weight = 1,
opacity = 1,
color = 'white',
fillOpacity = 0.7,
label = d$NAME) %>%
# add a basemap
addProviderTiles(providers$Esri.WorldGrayCanvas) %>%
# add a legend
addLegend(pal = pal, values = ~percent_biden,
opacity = 0.7, title = NULL,
position = 'bottomright')
p
Next week, we discuss the challenges and opportunities presented by data that is collected across multiple time periods. To prepare, please read and annotate Chapter 16 of R For Data Science.
Revise your map from last week based on our in-class feedback. Submit both a still image of your map from ggplot() and create an interactive version of the map with leaflet() to show off in class next week.
All the code is available on the repository at R/week-08/interactive-map-election-results-2020.R.↩︎